/**
 * @file   Date.cpp
 * @author Djuro Drljaca (djurodrljaca@gmail.com)
 * @date   2014-04-19
 * @brief  DON data type object: Date
 *
 * Copyright 2014  Djuro Drljaca (djurodrljaca@gmail.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <DON/Core/DataType/Date.h>
#include <DON/Core/DataType/UInt16.h>
#include <QtCore/QByteArray>

using namespace DON::Core::DataType;

class Date::Private
{
public:
    Private()
        : value(QDate())
    { }

    QDate value;
};

Date::Date()
    : AbstractDataType(),
      d(new Private())
{
}

Date::Date(const Date &other)
    : AbstractDataType(),
      d(new Private())
{
    d->value = other.d->value;
}

Date::~Date()
{
    delete d;
}

Date & Date::operator=(const Date &other)
{
    d->value = other.d->value;

    return *this;
}

AbstractDataType * Date::clone() const
{
    return new Date(*this);
}

DataType Date::getDataType() const
{
    return DataType_Date;
}

QDate Date::getValue() const
{
    return d->value;
}

void Date::setValue(const QDate &value)
{
    d->value = value;
}

bool Date::fromBinary(const QByteArray &data, const int startIndex, int *size)
{
    QDate value;
    bool success = false;

    const quint16 dateValue = UInt16::fromBinary(data, startIndex, &success);

    if (success)
    {
        const int day = static_cast<int>(dateValue & 0x1F);
        const int month = static_cast<int>((dateValue >> 5) & 0x0F);
        const int year = static_cast<int>((dateValue >> 9) & 0x7F) + 2000;

        value.setDate(year, month, day);

        success = value.isValid();
    }

    if (success)
    {
        d->value = value;

        if (size != NULL)
        {
            *size = 2;
        }
    }

    return success;
}

QByteArray Date::toBinary() const
{
    QByteArray data;
    const QDate &value = d->value;

    if (value.isValid())
    {
        const QDate minDate(2000, 1, 1);
        const QDate maxDate(2127, 12, 31);

        if ((value >= minDate) &&
            (value <= maxDate))
        {
            const int day = value.day();
            const int month = value.month();
            const int year = value.year() - 2000;

            quint16 dateValue = static_cast<quint16>(day) |
                                (static_cast<quint16>(month) << 5) |
                                (static_cast<quint16>(year) << 9);

            data.append(UInt16::toBinary(dateValue));
        }
    }

    return data;
}

Date * Date::fromAbstractDataType(AbstractDataType *instance)
{
    Date *outputInstance = NULL;

    if (instance != NULL)
    {
        if (instance->getDataType() == DataType_Date)
        {
            outputInstance = static_cast<Date *>(instance);
        }
    }

    return outputInstance;
}
